/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.common.util;

import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;

/**
 * Byte 操作工具类
 *
 * @author vacoor
 */
public abstract class Bytes {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    public static byte[] toBytes(int integer) {
        byte[] bytes = new byte[4];
        /*
        int shift = 24;
        for (int i = 0; i < bytes.length; i++, shift -= 8) {
            bytes[i] = (byte) ((integer >> shift) & 0xFF);
        }
        */
        bytes[0] = (byte) (0xFF & ((0xFF000000 & integer) >> 24));
        bytes[1] = (byte) (0xFF & ((0x00FF0000 & integer) >> 16));
        bytes[2] = (byte) (0xFF & ((0x0000FF00 & integer) >> 8));
        bytes[3] = (byte) (0xFF & integer);
        return bytes;
    }

    public static byte[] toBytes(long l) {
        byte[] bytes = new byte[8];
        /*
        int shift = 56;
        for (int i = 0; i < bytes.length; i++, shift -= 8) {
            bytes[i] = (byte) ((l >> shift) & 0xFF);
        }
        */
        bytes[0] = (byte) (0xFF & ((0xFF00000000000000L & l) >> 56));
        bytes[1] = (byte) (0xFF & ((0x00FF000000000000L & l) >> 48));
        bytes[2] = (byte) (0xFF & ((0x0000FF0000000000L & l) >> 40));
        bytes[3] = (byte) (0xFF & ((0x000000FF00000000L & l) >> 32));
        bytes[4] = (byte) (0xFF & ((0x00000000FF000000L & l) >> 24));
        bytes[5] = (byte) (0xFF & ((0x0000000000FF0000L & l) >> 16));
        bytes[6] = (byte) (0xFF & ((0x000000000000FF00L & l) >> 8));
        bytes[7] = (byte) (0xFF & l);
        return bytes;
    }

    public static byte[] toBytes(char[] chars) {
        return toBytes(new String(chars), DEFAULT_CHARSET);
    }

    public static byte[] toBytes(String text) {
        return toBytes(text, DEFAULT_CHARSET);
    }

    public static byte[] toBytes(String text, Charset charset) {
        return text.getBytes(charset);
    }

    public static int toInt(byte[] bytes) {
        if (bytes.length > 4) {
            throw new IllegalArgumentException("bytes length must not be greater than 4");
        }
        int shift = 0;
        int result = 0;
        for (int i = bytes.length - 1; i >= 0; i--, shift += 8) {
            result |= ((bytes[i] & 0xFF) << shift);
        }
        return result;
        // return ((0xFF & bytes[3]) | ((0xFF & bytes[2]) << 8) | ((0xFF & bytes[1]) << 16) | ((0xFF & bytes[0]) << 24));
    }

    public static long toLong(byte[] bytes) {
        if (bytes.length > 8) {
            throw new IllegalArgumentException("bytes length must not be greater than 8");
        }
        int shift = 0;
        long result = 0;
        for (int i = bytes.length - 1; i >= 0; i--, shift += 8) {
            result |= ((long) (bytes[i] & 0xFF) << shift);
        }
        return result;
    }

    public static String toString(byte[] bytes) {
        return toString(bytes, DEFAULT_CHARSET);
    }

    public static String toString(byte[] bytes, Charset charset) {
        return new String(bytes, charset);
    }

    public static char[] toChars(byte[] bytes) {
        return toChars(bytes, DEFAULT_CHARSET);
    }

    public static char[] toChars(byte[] bytes, Charset charset) {
        return toString(bytes, charset).toCharArray();
    }

    public static byte[] toBytes(Object o) {
        if (o == null) {
            String msg = "Argument for String conversion cannot be null.";
            throw new IllegalArgumentException(msg);
        }
        if (o instanceof Integer) {
            return toBytes(((Integer) o).intValue());
        } else if (o instanceof Long) {
            return toBytes(((Long) o).longValue());
        } else if (o instanceof byte[]) {
            return (byte[]) o;
        } else if (o instanceof char[]) {
            return toBytes((char[]) o);
        } else if (o instanceof String) {
            return toBytes((String) o);
        } else if (o instanceof File) {
            return toBytes((File) o);
        } else if (o instanceof URL) {
            return toBytes((URL) o);
        } else if (o instanceof InputStream) {
            return toBytes((InputStream) o);
        } else {
            return objectToBytes(o);
        }
    }

    private static byte[] objectToBytes(Object o) {
        throw new UnsupportedOperationException("unsupported object cast to bytes");
    }

    protected static byte[] toBytes(File file) {
        if (file == null) {
            throw new IllegalArgumentException("File argument cannot be null.");
        }
        try {
            return toBytes(new FileInputStream(file));
        } catch (FileNotFoundException e) {
            throw Throwables.unchecked(e);
        }
    }

    protected static byte[] toBytes(URL url) {
        if (url == null) {
            throw new IllegalArgumentException("Url argument cannot be null.");
        }
        try {
            return toBytes(url.openStream());
        } catch (IOException e) {
            throw Throwables.unchecked(e);
        }
    }

    protected static byte[] toBytes(InputStream in) {
        if (in == null) {
            throw new IllegalArgumentException("InputStream argument cannot be null.");
        }
        try {
            return IOUtils.readBytes(in, true);
        } catch (IOException e) {
            throw Throwables.unchecked(e);
        }
    }

    private Bytes() {
    }
}
